New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@cdellacqua/signals

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cdellacqua/signals

A simple signal pattern implementation that enables reactive programming

  • 4.1.2
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

@cdellacqua/signals

A simple signal pattern implementation that enables reactive programming.

Signals are event emitters with specific purposes. For example:

button.addEventListener('click', () => console.log('click'));
input.addEventListener('change', (e) => console.log(e));

...could be rewritten with signals as:

button.clicked.subscribe(() => console.log('click'));
input.changed.subscribe((e) => console.log(e));

NPM Package

npm install @cdellacqua/signals

Documentation

Highlights

Signal<T> provides methods such as:

  • emit(value), to emit a value to all subscribers;
  • subscribe(subscriber), to attach subscribers;
  • subscribeOnce(subscriber), to attach subscribers for a single emit call.

When you subscribe to a signal, you get a unsubscribe function, e.g.:

import {makeSignal} from '@cdellacqua/signals';

const signal$ = makeSignal<number>();
const unsubscribe = signal$.subscribe((v) => console.log(v));
signal$.emit(3.14); // will trigger console.log, printing 3.14
unsubscribe();
signal$.emit(42); // won't do anything

The above code can be rewritten with subscribeOnce:

import {makeSignal} from '@cdellacqua/signals';

const signal$ = makeSignal<number>();
signal$.subscribeOnce((v) => console.log(v));
signal$.emit(3.14); // will trigger console.log, printing 3.14
signal$.emit(42); // won't do anything

Signal<T> also contains a getter (nOfSubscriptions) that lets you know how many active subscriptions are active at a given moment (this could be useful if you are trying to optimize your code).

import {makeSignal} from '@cdellacqua/signals';

const signal$ = makeSignal<number>();
console.log(signal$.nOfSubscriptions); // 0
const unsubscribe = signal$.subscribe(() => undefined); // empty subscriber
console.log(signal$.nOfSubscriptions); // 1
unsubscribe();
console.log(signal$.nOfSubscriptions); // 0

A nice feature of Signal<T> is that it deduplicates subscribers, that is you can't accidentally add the same function more than once to the same signal (just like the DOM addEventListener method):

import {makeSignal} from '@cdellacqua/signals';

const signal$ = makeSignal<number>();
const subscriber = (v: number) => console.log(v);
console.log(signal$.nOfSubscriptions); // 0
const unsubscribe1 = signal$.subscribe(subscriber);
const unsubscribe2 = signal$.subscribe(subscriber);
const unsubscribe3 = signal$.subscribe(subscriber);
console.log(signal$.nOfSubscriptions); // 1
unsubscribe3(); // will remove "subscriber"
unsubscribe2(); // won't do anything, "subscriber" has already been removed
unsubscribe1(); // won't do anything, "subscriber" has already been removed
console.log(signal$.nOfSubscriptions); // 0

If you ever needed to add the same function more than once you can still achieve that by simply wrapping it inside an arrow function:

import {makeSignal} from '@cdellacqua/signals';

const signal$ = makeSignal<number>();
const subscriber = (v: number) => console.log(v);
console.log(signal$.nOfSubscriptions); // 0
const unsubscribe1 = signal$.subscribe(subscriber);
console.log(signal$.nOfSubscriptions); // 1
const unsubscribe2 = signal$.subscribe((v) => subscriber(v));
console.log(signal$.nOfSubscriptions); // 2
unsubscribe2();
console.log(signal$.nOfSubscriptions); // 1
unsubscribe1();
console.log(signal$.nOfSubscriptions); // 0

You can also have a signal that just triggers its subscribers without passing any data:

import {makeSignal} from '@cdellacqua/signals';

const signal$ = makeSignal<void>();
signal$.emit();

Coalescing and deriving signals

Coalescing

Coalescing multiple signals into one consists of creating a new signal that will emit the latest value emitted by any source signal.

Example:

import {makeSignal, coalesceSignals} from '@cdellacqua/signals';

const lastUpdate1$ = makeSignal<number>();
const lastUpdate2$ = makeSignal<number>();
const latestUpdate$ = coalesceSignals([lastUpdate1$, lastUpdate2$]);
latestUpdate$.subscribe((v) => console.log(v));
lastUpdate1$.emit(1577923200000); // will log 1577923200000
lastUpdate2$.emit(1653230659450); // will log 1653230659450

Deriving

Deriving a signal consists of creating a new signal that emits a value mapped from the source signal.

Example:

import {makeSignal, deriveSignal} from '@cdellacqua/signals';

const signal$ = makeSignal<number>();
const derived$ = deriveSignal(signal$, (n) => n + 100);
derived$.subscribe((v) => console.log(v));
signal$.emit(3); // will trigger console.log, echoing 103

Readonly signal

When you coalesce or derive a signal, you get back a ReadonlySignal<T>. This type lacks the emit method.

A Signal<T> is in fact an extension of a ReadonlySignal<T> that adds the emit method.

As a rule of thumb, it is preferable to pass around ReadonlySignal<T>s, to better encapsulate your signals and prevent unwanted emits.

Keywords

FAQs

Package last updated on 15 Jul 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc